/*
 * @Autor: PK
 * @Date: 2021-03-31 13:34:14
 * @Description: 集合工具类，看方法名就行
 */
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ShkSimulation.core.dao.statistic;
using ShkSimulation.core.exceptions;
using ShkSimulation.core.factory;

namespace ShkSimulation.core.util
{
    public static class CollectionUtil{
        
        public static List<T> RandomGet<T>(IList<T> collection, int number){
            List<T> list = new List<T>(number);
            if(number <= 0 || collection == null || collection.Count == 0){
                return list;
            }
            int size = collection.Count;
            if(size <= number){
                return new List<T>(collection);
            }
            Random random = new Random();
            for(int i = 0; i < size;i++){
                if(i < number){
                    list.Add(collection[i]);
                }else{
                    int canAdd = random.Next();
                    if(canAdd < number){
                        T temp = collection[i];
                        collection[i] = collection[canAdd];
                        collection[canAdd] = temp;
                    }
                }
            }
            return list;
        }

        public static object[,] DataTableToArray(DataTable dataTable) {
            if (dataTable == null || dataTable.Rows.Count == 0 || dataTable.Columns.Count == 0) {
                return new object[0, 0];
            }
            object[,] result = new object[dataTable.Rows.Count, dataTable.Columns.Count];
            for (var i = 0; i < dataTable.Rows.Count; i++) {
                for (int j = 0; j < dataTable.Rows[i].ItemArray.Length; j++) {
                    result[i,j] = dataTable.Rows[i].ItemArray[j];
                }
            }
            return result;
        }
        
        public static string[] GetDataTableHeader(DataTable dataTable) {
            string[] headers;
            if (dataTable == null || (dataTable.Columns.Count) == 0) {
                headers = Array.Empty<string>();
            } else {
                headers = dataTable.Columns
                    .Cast<DataColumn>()
                    .Select(column => column.ColumnName)
                    .ToArray();
            }
            return headers;
        }
        
        public static Dictionary<int, CreateParam> DataTableToIndexCreateParams(DataTable dataTable) {
            string[] headers = CollectionUtil.GetDataTableHeader(dataTable);
            if (CollectionUtil.ArrayElementDuplicated(headers)) {
                List<string> repeatSequence = CollectionUtil.GetRepeatSequence(headers);
                throw new ErrorParamException("同一数据表格不能有重复列名：" + string.Join(", ", repeatSequence));
            }
            List<Dictionary<string, object>> data = DataTableToDictionary(dataTable);
            int index = 0;
            return data.Select(each => CreateParam.Create(each)).ToDictionary(_ => index++, each => each);
        }

        
        public static List<CreateParam> DataTableToCreateParams(DataTable dataTable) {
            if (dataTable == null) {
                return new List<CreateParam>();
            }
            string[] headers = CollectionUtil.GetDataTableHeader(dataTable);
            if (CollectionUtil.ArrayElementDuplicated(headers)) {
                List<string> repeatSequence = CollectionUtil.GetRepeatSequence(headers);
                throw new ErrorParamException("同一数据表格不能有重复列名：" + string.Join(", ", repeatSequence));
            }
            List<Dictionary<string, object>> data = DataTableToDictionary(dataTable);
            return data.Select(each => CreateParam.Create(each)).ToList();
        }
        
        public static List<Dictionary<string, object>> DataTableToDictionary(DataTable dataTable) {
            List<Dictionary<string, object>> result = new List<Dictionary<string, object>>();
            if (dataTable == null || dataTable.Columns.Count == 0 || dataTable.Rows.Count == 0) {
                return new List<Dictionary<string, object>>();
            }            
            string[] headers = GetDataTableHeader(dataTable);
            foreach (DataRow row in dataTable.Rows) {
                Dictionary<string, object> line = new Dictionary<string, object>();
                for (int i = 0; i < row.ItemArray.Length; i++) {
                    line.Add(headers[i], row.ItemArray[i]);
                }
                result.Add(line);
            }
            return result;
        }
        
        public static bool ArrayElementDuplicated(string[] headers) {
            return headers.GroupBy(x => x).Any(group => group.Count() > 1);
        }        
        
        public static List<string> GetRepeatSequence(string[] headers) {
            return headers.GroupBy(str => str)
                .Where(group => group.Count() > 1)
                .Select(group => group.Key)
                .ToList();
        }

        public static List<int> Divide(int runDays, int size) {
            if (runDays < 0 || size <= 0) {
                throw new ErrorParamException("runDays和size不能小于0");
            }
            List<int> result = new List<int>();
            int rest = runDays % size;
            int times = runDays / size;
            for (int i = 0; i < times; i++) {
                result.Add(size);
            }
            if (rest > 0) {
                result.Add(rest);
            }
            return result;
        }
        
        public static List<List<T>> Divide<T>(IList<T> collection, int size) {
            if (size <= 0) {
                throw new ErrorParamException("size不能小于0");
            }
            if (collection.Count <= size) {
                return new List<List<T>>() { new List<T>(collection) };
            }
            int count = collection.Count;
            List<List<T>> result = new List<List<T>>();
            int rest = count % size;
            int times = count / size;
            int index = 0;
            for (int i = 0; i < times; i++) {
                List<T> temp = new List<T>();
                for (int j = 0; j < size; j++) {
                    temp.Add(collection[index++]);
                }
                result.Add(temp);
            }
            if (rest > 0) {
                List<T> temp = new List<T>();
                for (int i = 0; i < rest; i++) {
                    temp.Add(collection[index++]);
                }
                result.Add(temp);
            }
            return result;
        }

        public static List<int> StringToList(string agencyIds) {
            if (agencyIds == null) {
                return new List<int>();
            }
            agencyIds = Regex.Replace(agencyIds, @"\s", "");
            string[] ids = Regex.Split(agencyIds, @",|，", RegexOptions.Compiled);
            if (ids.Length <= 1) {
                int temp;
                if (int.TryParse(ids[0], out temp)) {
                    return new List<int>(){temp};
                }
                return new List<int>();
            }
            return ids.Where(each => each.Length > 0).Select(each => Convert.ToInt32(each)).ToList();
        }

        public static void AddRange<K, V>(this Dictionary<K, V> dictionary, 
            Dictionary<K, V> toAdd) {
            foreach (var (key, value) in toAdd) {
                if (dictionary.ContainsKey(key)) {
                    throw new ErrorParamException($"Dictionary相加错误，已存在: {key}");
                }
                dictionary.Add(key, value);
            }
        }
        
        public static void AddRange(this List<DataReporterCollection> dictionary, 
            List<DataReporterCollection> toAdd) {
            var unique = dictionary.ToDictionary(each => each.Uniquekey);
            foreach (var reporterCollection in toAdd) {
                if (unique.ContainsKey(reporterCollection.Uniquekey)) {
                    throw new ErrorParamException($"不允许添加相同UniqueKey的DataReporterCollection: {reporterCollection.Uniquekey}");
                }
                dictionary.Add(reporterCollection);
            }
        }
        
        
        public static string StringLimitJoin(IList<string> sequence, int length, string tail = "...") {
            if (sequence == null || sequence.Count == 0) {
                return "空";
            }
            StringBuilder builder = new StringBuilder(sequence[0]);
            for (var i = 1; i < sequence.Count; i++) {
                if (builder.Length <= length) {
                    builder.Append(", ").Append(sequence[i]);
                } else {
                    return $"{builder}...";
                }
            }
            return builder.ToString();
        }

    }
}